home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / larn.lha / spells.c < prev    next >
C/C++ Source or Header  |  1995-11-19  |  27KB  |  822 lines

  1. /*
  2.   cast()             Subroutine called by parse to cast a spell for the user
  3.   speldamage(x)      Function to perform spell functions cast by the player
  4.   loseint()          Routine to decrement your int (intelligence) if > 3
  5.   isconfuse()        Routine to check to see if player is confused
  6.   nospell(x,monst)   Routine to return 1 if a spell doesn't affect a monster
  7.   fullhit(xx)        Function to return full damage against a monst (aka web)
  8.   direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
  9.   godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
  10.   ifblind(x,y)       Routine to put "monster" or the monster name into lastmosnt
  11.   tdirect(spnum)     Routine to teleport away a monster
  12.   omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
  13.   dirsub(x,y)        Routine to ask for direction, then modify x,y for it
  14.   dirpoly(spnum)     Routine to ask for a direction and polymorph a monst
  15.   annihilate()   Routine to annihilate monsters around player, playerx,playery
  16.   genmonst()         Function to ask for monster and genocide from game
  17. */
  18.  
  19. #include "header.h"
  20. #include "larndefs.h"
  21. #include "objects.h"
  22. #include "monsters.h"
  23. #include "player.h"
  24. #include <ctype.h>
  25.  
  26. #define min(x,y) (((x)>(y))?(y):(x))
  27. #define max(x,y) (((x)>(y))?(x):(y))
  28.  
  29. struct isave    /* used for altar reality */
  30.     {
  31.     char type;  /* 0=item,  1=monster */
  32.     char id;    /* item number or monster number */
  33.     short arg;  /* the type of item or hitpoints of monster */
  34.     };
  35.  
  36. /* Forward declarations
  37. */
  38. static void create_guardian();
  39. extern hitm();
  40. extern char spelweird[MAXMONST+8][SPNUM];
  41.  
  42. /*
  43.  *  cast()      Subroutine called by parse to cast a spell for the user
  44.  *
  45.  *  No arguments and no return value.
  46.  */
  47. static char eys[] = "\nEnter your spell: ";
  48. cast()
  49.     {
  50.     register int i,j,a,b,d;
  51.     cursors();
  52.     if (c[SPELLS]<=0) 
  53.         {   
  54.         lprcat("\nYou don't have any spells!"); 
  55.         return; 
  56.         }
  57.     lprcat(eys);
  58.     --c[SPELLS];
  59.     while ((a=ttgetch())=='I')
  60.         { 
  61.         seemagic(-1); 
  62.         cursors();  
  63.         lprcat(eys);
  64.         }
  65.     if (a=='\33') 
  66.         goto over;                  /*  to escape casting a spell   */
  67.     if ((b=ttgetch())=='\33') 
  68.         goto over;                  /*  to escape casting a spell   */
  69.     if ((d=ttgetch())=='\33')
  70.         { 
  71. over: 
  72.         lprcat(aborted); 
  73.         c[SPELLS]++; 
  74.         return;
  75.         }                           /*  to escape casting a spell   */
  76. #ifdef EXTRA
  77.     c[SPELLSCAST]++;
  78. #endif
  79.     for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
  80.         if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
  81.             if (spelknow[i])
  82.                 {  speldamage(i);  j = 1;  i=SPNUM; }
  83.  
  84.     if (j == -1) lprcat("  Nothing Happened ");
  85.     bottomline();
  86.     }
  87.  
  88. /*
  89.  *  speldamage(x)       Function to perform spell functions cast by the player
  90.  *      int x;
  91.  *
  92.  *  Enter with the spell number, returns no value.
  93.  *  Please insure that there are 2 spaces before all messages here
  94.  */
  95. static speldamage(x)
  96.     int x;
  97.     {
  98.     register int i,j,clev;
  99.     int xl,xh,yl,yh;
  100.     register char *p,*kn,*pm;
  101.  
  102.     if (x>=SPNUM) return;   /* no such spell */
  103.     if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
  104.     clev = c[LEVEL];
  105.     if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
  106.         { lprcat("  It didn't work!");  return; }
  107.     if (clev*3+2 < x)
  108.     {
  109.     lprcat("  Nothing happens.  You seem inexperienced at this");
  110.     return;
  111.     }
  112.  
  113.     switch(x)
  114.         {
  115. /* ----- LEVEL 1 SPELLS ----- */
  116.  
  117.         case 0: if (c[PROTECTIONTIME]==0)   c[MOREDEFENSES]+=2; /* protection field +2 */
  118.                 c[PROTECTIONTIME] += 250;   return;
  119.  
  120.         case 1: i = rnd(((clev+1)<<1)) + clev + 3;
  121.                 godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
  122.  
  123.                 return;
  124.  
  125.         case 2: if (c[DEXCOUNT]==0) c[DEXTERITY]+=3; /* dexterity   */
  126.                 c[DEXCOUNT] += 400;     return;
  127.  
  128.         case 3: i=rnd(3)+1;
  129.                 p="  While the %s slept, you smashed it %d times";
  130.             ws: direct(x,fullhit(i),p,i); /*    sleep   */  return;
  131.  
  132.         case 4: /*  charm monster   */  c[CHARMCOUNT] += c[CHARISMA]<<1;    return;
  133.  
  134.         case 5: godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /* sonic spear */
  135.                 return;
  136.  
  137. /* ----- LEVEL 2 SPELLS ----- */
  138.  
  139.         case 6: i=rnd(3)+2; p="  While the %s is entangled, you hit %d times";
  140.                 goto ws; /* web */
  141.  
  142.         case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3; /*  strength    */
  143.                 c[STRCOUNT] += 150+rnd(100);    return;
  144.  
  145.         case 8: yl = playery-5;     /* enlightenment */
  146.                 yh = playery+6;   xl = playerx-15;   xh = playerx+16;
  147.                 vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
  148.                 for (i=yl; i<=yh; i++) /* enlightenment */
  149.                     for (j=xl; j<=xh; j++)
  150.                         know[j][i]=KNOWALL;
  151.                 draws(xl,xh+1,yl,yh+1); return;
  152.  
  153.         case 9: raisehp(20+(clev<<1));  return;  /* healing */
  154.  
  155.         case 10:    c[BLINDCOUNT]=0;    return; /* cure blindness   */
  156.  
  157.         case 11:    createmonster(makemonst(level+1)+8);  return;
  158.  
  159.         case 12:    if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
  160.                     else lprcat("  It didn't believe the illusions!");
  161.                     return;
  162.  
  163.         case 13:    /* if he has the amulet of invisibility then add more time */
  164.                     for (j=i=0; i<26; i++)
  165.                         if (iven[i]==OAMULET) j+= 1+ivenarg[i];
  166.                     c[INVISIBILITY] += (j<<7)+12;   return;
  167.  
  168. /* ----- LEVEL 3 SPELLS ----- */
  169.  
  170.         case 14:    godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*    fireball */
  171.  
  172.         case 15:    godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');    /*  cold */
  173.                     return;
  174.  
  175.         case 16:    dirpoly(x);  return;    /*  polymorph */
  176.  
  177.         case 17:    c[CANCELLATION]+= 5+clev;   return; /*  cancellation    */
  178.  
  179.         case 18:    c[HASTESELF]+= 7+clev;  return;  /* haste self  */
  180.  
  181.         case 19:    omnidirect(x,30+rnd(10),"  The %s gasps for air");  /* cloud kill */
  182.                     return;
  183.  
  184.         case 20:    xh = min(playerx+1,MAXX-2);     yh = min(playery+1,MAXY-2);
  185.                     for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
  186.                       for (j=max(playery-1,1); j<=yh; j++)
  187.                         {
  188.                         kn = &know[i][j];
  189.                             pm = &mitem[i][j];
  190.                         switch(*(p= &item[i][j]))
  191.                           {
  192.                           case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
  193.                                             *p = *kn = 0;
  194.                                         break;
  195.  
  196.                           case OSTATUE: if (c[HARDGAME]<3)
  197.                                              {
  198.                                              *p=OBOOK; iarg[i][j]=level;  *kn=0;
  199.                                              }
  200.                                         break;
  201.  
  202.               case OTHRONE:
  203.                   *p= OTHRONE2;
  204.                   create_guardian( GNOMEKING, i, j );
  205.                   break;
  206.  
  207.               case OALTAR:
  208.                   create_guardian( DEMONPRINCE, i, j );
  209.                   break;
  210.  
  211.               case OFOUNTAIN:
  212.                   create_guardian( WATERLORD, i, j );
  213.                   break;
  214.               };
  215.                         switch(*pm)
  216.                             {
  217.                             case XORN:  ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
  218.                             }
  219.                         }
  220.                     return;
  221.  
  222. /* ----- LEVEL 4 SPELLS ----- */
  223.  
  224.         case 21:    direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
  225.                     return;
  226.  
  227.         case 22:    godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');    /*  lightning */
  228.                     return;
  229.  
  230.         case 23:    i=min(c[HP]-1,c[HPMAX]/2);  /* drain life */
  231.                     direct(x,i+i,"",0); c[HP] -= i;     return;
  232.  
  233.         case 24:    if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
  234.                     c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
  235.                     return;
  236.  
  237.         case 25:    omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
  238.                     return;
  239.  
  240.         case 26:    if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
  241.                     if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
  242.                     else lprcat("  It didn't work"); return;
  243.  
  244. /* ----- LEVEL 5 SPELLS ----- */
  245.  
  246.         case 27:    c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
  247.  
  248.         case 28:    c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
  249.  
  250.         case 29:    c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
  251.  
  252.         case 30:    tdirect(x);  return;  /* teleport away */
  253.  
  254.         case 31:    omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
  255.                     return;
  256.  
  257. /* ----- LEVEL 6 SPELLS ----- */
  258.  
  259.         case 32:    if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
  260.                         {
  261.                         beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
  262.                         nap(4000);  died(258); return;
  263.                         }
  264.                     xl=playerx; yl=playery;
  265.                     loseint();
  266.                     i=dirsub(&xl,&yl); /* get direction of sphere */
  267.                     newsphere(xl,yl,i,rnd(20)+11);  /* make a sphere */
  268.                     return;
  269.  
  270.         case 33:    genmonst();  spelknow[33]=0;  /* genocide */
  271.                     loseint();
  272.                     return;
  273.  
  274.         case 34:    /* summon demon */
  275.                     if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
  276.                     if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
  277.                     lprcat("  The demon turned on you and vanished!"); beep();
  278.                     i=rnd(40)+30;  lastnum=277;
  279.                     losehp(i); /* must say killed by a demon */ return;
  280.  
  281.         case 35:    /* walk through walls */
  282.                     c[WTW] += rnd(10)+5;    return;
  283.  
  284.         case 36:    /* alter reality */
  285.                     {
  286.                     struct isave *save; /* pointer to item save structure */
  287.                     int sc; sc=0;   /* # items saved */
  288.                     save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
  289.             if (save == NULL)
  290.             {
  291.             lprcat("\nPolinneaus won't let you mess with his dungeon!");
  292.             return;
  293.             }
  294.             for (j=0; j<MAXY; j++)
  295.                         for (i=0; i<MAXX; i++) /* save all items and monsters */
  296.                             {
  297.                             xl = item[i][j];
  298.                             if (xl && xl!=OWALL && xl!=OANNIHILATION) 
  299.                                 {
  300.                                 save[sc].type=0;  save[sc].id=item[i][j];
  301.                                 save[sc++].arg=iarg[i][j];
  302.                                 }
  303.                             if (mitem[i][j]) 
  304.                                 {
  305.                                 save[sc].type=1;  save[sc].id=mitem[i][j];
  306.                                 save[sc++].arg=hitp[i][j];
  307.                                 }
  308.                             item[i][j]=OWALL;   mitem[i][j]=0;
  309.                         if (wizard)
  310.                             know[i][j]=KNOWALL;
  311.                         else
  312.                             know[i][j]=0;
  313.                             }
  314.                     eat(1,1);   if (level==1) item[33][MAXY-1]=OENTRANCE;
  315.                     for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
  316.                     while (sc>0) /* put objects back in level */
  317.                         {
  318.                         --sc;
  319.                         if (save[sc].type == 0)
  320.                             {
  321.                             int trys;
  322.                             for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
  323.                             if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
  324.                             }
  325.                         else
  326.                             { /* put monsters back in */
  327.                             int trys;
  328.                             for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
  329.                             if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
  330.                             }
  331.                         }
  332.                     loseint();
  333.                     draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
  334.                     free((char*)save);   positionplayer();  return;
  335.                     }
  336.  
  337.         case 37:    /* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
  338.                     loseint();
  339.                     return;
  340.  
  341.         default:    lprintf("  spell %d not available!",(long)x); beep();  return;
  342.         };
  343.     }
  344.  
  345. /*
  346.     Create a guardian for a throne/altar/fountain, as a result of the player
  347.     using a VPR spell or pulverization scroll on it.
  348. */
  349. static void create_guardian( monst, x, y )
  350. int monst;  /* monster code for the guardian */
  351. int x, y;   /* coords of the object being guarded */
  352.     {
  353.     int k ;
  354.  
  355.     /* prevent the guardian from being created on top of the player
  356.     */
  357.     if ((x == playerx) && (y == playery))
  358.     {
  359.     k = rnd(8);
  360.     x += diroffx[k];
  361.     y += diroffy[k];
  362.     }
  363.     know[x][y] = 0;
  364.     mitem[x][y] = monst ;
  365.     hitp[x][y]  = monster[monst].hitpoints;
  366.     }
  367.  
  368. /*
  369.  *  loseint()       Routine to subtract 1 from your int (intelligence) if > 3
  370.  *
  371.  *  No arguments and no return value
  372.  */
  373. static loseint()
  374.     {
  375.     if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
  376.     }
  377.  
  378. /*
  379.  *  isconfuse()         Routine to check to see if player is confused
  380.  *
  381.  *  This routine prints out a message saying "You can't aim your magic!"
  382.  *  returns 0 if not confused, non-zero (time remaining confused) if confused
  383.  */
  384. static isconfuse()
  385.     {
  386.     if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
  387.     return(c[CONFUSE]);
  388.     }
  389.  
  390. /*
  391.  *  nospell(x,monst)    Routine to return 1 if a spell doesn't affect a monster
  392.  *      int x,monst;
  393.  *
  394.  *  Subroutine to return 1 if the spell can't affect the monster
  395.  *    otherwise returns 0
  396.  *  Enter with the spell number in x, and the monster number in monst.
  397.  */
  398. static nospell(x,monst)
  399.     int x,monst;
  400.     {
  401.     register int tmp;
  402.     if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
  403.     if ((tmp=spelweird[monst-1][x])==0) return(0);
  404.     cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
  405.     }
  406.  
  407. /*
  408.  *  fullhit(xx)     Function to return full damage against a monster (aka web)
  409.  *      int xx;
  410.  *
  411.  *  Function to return hp damage to monster due to a number of full hits
  412.  *  Enter with the number of full hits being done
  413.  */
  414. fullhit(xx)
  415.     int xx;
  416.     {
  417.     register int i;
  418.     if (xx<0 || xx>20) return(0);   /* fullhits are out of range */
  419.     if (c[LANCEDEATH]) return(10000);   /* lance of death */
  420.     i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
  421.     return( (i>=1) ? i : xx );
  422.     }
  423.  
  424. /*
  425.  *  direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
  426.  *      int spnum,dam,arg;
  427.  *      char *str;
  428.  *
  429.  *  Routine to ask for a direction to a spell and then hit the monster
  430.  *  Enter with the spell number in spnum, the damage to be done in dam,
  431.  *    lprintf format string in str, and lprintf's argument in arg.
  432.  *  Returns no value.
  433.  */
  434. static direct(spnum,dam,str,arg)
  435.     int spnum,dam,arg;
  436.     char *str;
  437.     {
  438.     extern char lastmonst[];
  439.     int x,y;
  440.     register int m;
  441.     if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
  442.     if (isconfuse()) return;
  443.     dirsub(&x,&y);
  444.     m = mitem[x][y];
  445.     if (item[x][y]==OMIRROR)
  446.         {
  447.         if (spnum==3) /* sleep */
  448.             {
  449.             lprcat("You fall asleep! "); beep();
  450.         fool:
  451.             arg += 2;
  452.             while (arg-- > 0) { parse2(); nap(1000); }
  453.             return;
  454.             }
  455.         else if (spnum==6) /* web */
  456.             {
  457.             lprcat("You get stuck in your own web! "); beep();
  458.             goto fool;
  459.             }
  460.         else
  461.             {
  462.             lastnum=278; 
  463.             lprintf(str,"spell caster (thats you)",(long)arg);
  464.             beep(); losehp(dam); return;
  465.             }
  466.         }
  467.     if (m==0)
  468.         {   lprcat("  There wasn't anything there!");   return;  }
  469.     ifblind(x,y);
  470.     if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  471.     lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
  472.     }
  473.  
  474. /*
  475.  *  godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
  476.  *      int spnum,dam,delay;
  477.  *      char *str,cshow;
  478.  *
  479.  *  Function to hit in a direction from a missile weapon and have it keep
  480.  *  on going in that direction until its power is exhausted
  481.  *  Enter with the spell number in spnum, the power of the weapon in hp,
  482.  *    lprintf format string in str, the # of milliseconds to delay between 
  483.  *    locations in delay, and the character to represent the weapon in cshow.
  484.  *  Returns no value.
  485.  */
  486. godirect(spnum,dam,str,delay,cshow)
  487.     int spnum,dam,delay;
  488.     char *str,cshow;
  489.     {
  490.     extern char lastmonst[] ;
  491.     register char *p;
  492.     register int x,y,m;
  493.     int dx,dy;
  494.     if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
  495.     if (isconfuse()) return;
  496.     dirsub(&dx,&dy);    x=dx;   y=dy;
  497.     dx = x-playerx;     dy = y-playery;     x = playerx;    y = playery;
  498.     while (dam>0)
  499.         {
  500.         x += dx;    y += dy;
  501.         if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
  502.             {
  503.             dam=0;  break;  /* out of bounds */
  504.             }
  505.         if ((x==playerx) && (y==playery)) /* if energy hits player */
  506.             {
  507.             cursors(); lprcat("\nYou are hit my your own magic!"); beep();
  508.             lastnum=278;  losehp(dam);  return;
  509.             }
  510.         if (c[BLINDCOUNT]==0) /* if not blind show effect */
  511.             {
  512.             cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
  513.             }
  514.         if ((m=mitem[x][y]))    /* is there a monster there? */
  515.             {
  516.             ifblind(x,y);
  517.             if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  518.             cursors(); lprc('\n');
  519.             lprintf(str,lastmonst);     dam -= hitm(x,y,dam);
  520.             show1cell(x,y);  nap(1000);     x -= dx;    y -= dy;
  521.             }
  522.         else switch (*(p= &item[x][y]))
  523.             {
  524.         case OWALL:
  525.         cursors();
  526.         lprc('\n');
  527.         lprintf(str,"wall");
  528.         if (dam>=50+c[HARDGAME]) /* enough damage? */
  529.             if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
  530.             if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
  531.                             {
  532.                             lprcat("  The wall crumbles");
  533.                 *p=0;
  534.                 know[x][y]=0;
  535.                             show1cell(x,y);
  536.                             }
  537.         dam = 0;
  538.         break;
  539.  
  540.         case OCLOSEDDOOR:
  541.         cursors();
  542.         lprc('\n');
  543.         lprintf(str,"door");
  544.         if (dam>=40)
  545.             {
  546.             lprcat("  The door is blasted apart");
  547.             *p = 0;
  548.             know[x][y] = 0;
  549.             show1cell( x, y );
  550.             }
  551.         dam = 0 ;
  552.         break;
  553.  
  554.         case OSTATUE:
  555.         cursors();
  556.         lprc('\n');
  557.         lprintf(str,"statue");
  558.         if (c[HARDGAME]<3)
  559.             if (dam>44)
  560.             {
  561.             lprcat("  The statue crumbles");
  562.             *p=OBOOK;
  563.             iarg[x][y]=level;
  564.             know[x][y] = 0;
  565.             show1cell( x, y );
  566.             }
  567.         dam = 0 ;
  568.         break;
  569.  
  570.         case OTHRONE:
  571.         cursors();
  572.         lprc('\n');
  573.         lprintf(str,"throne");
  574.         if (dam>39)
  575.             {
  576.             *p = OTHRONE2;
  577.             create_guardian( GNOMEKING, x, y );
  578.             show1cell( x, y );
  579.             }
  580.         dam = 0;
  581.         break;
  582.  
  583.         case OALTAR:
  584.         cursors();
  585.         lprc('\n');
  586.         lprintf(str, "altar");
  587.         if ( dam > 75 - ( c[HARDGAME] >> 2 ))
  588.             {
  589.             create_guardian( DEMONPRINCE, x, y );
  590.             show1cell( x, y );
  591.             }
  592.         dam = 0 ;
  593.         break;
  594.  
  595.         case OFOUNTAIN:
  596.         cursors();
  597.         lprc('\n');
  598.         lprintf(str, "fountain");
  599.         if ( dam > 55 )
  600.             {
  601.             create_guardian( WATERLORD, x, y );
  602.             show1cell( x, y );
  603.             }
  604.         dam = 0 ;
  605.         break;
  606.  
  607.         case OMIRROR:
  608.     {
  609.     int bounce = FALSE, odx=dx, ody=dy ;
  610.         /* spells may bounce directly back or off at an angle
  611.         */
  612.         if (rnd(100) < 50 )
  613.         {
  614.         bounce = TRUE ;
  615.         dx *= -1;
  616.         }
  617.         if (rnd(100) < 50 )
  618.         {
  619.         bounce = TRUE ;
  620.         dy *= -1;
  621.         }
  622.     if (!bounce || ((odx==dx) && (ody==dy)))    /* guarentee a bounce */
  623.         {
  624.     dx = -odx;
  625.     dy = -ody;
  626.         }
  627.         }
  628.         break;
  629.             };
  630.         dam -= 3 + (c[HARDGAME]>>1);
  631.         }
  632.     }
  633.  
  634. /*
  635.  *  ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
  636.  *      int x,y;
  637.  *
  638.  *  Subroutine to copy the word "monster" into lastmonst if the player is blind
  639.  *  Enter with the coordinates (x,y) of the monster
  640.  *  Returns no value.
  641.  */
  642. ifblind(x,y)
  643.     int x,y;
  644.     {
  645.     extern char lastmonst[] ;
  646.     char *p;
  647.     vxy(&x,&y); /* verify correct x,y coordinates */
  648.     if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
  649.         else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
  650.     strcpy(lastmonst,p);
  651.     }
  652.  
  653. /*
  654.  *  tdirect(spnum)      Routine to teleport away a monster
  655.  *      int spnum;
  656.  *
  657.  *  Routine to ask for a direction to a spell and then teleport away monster
  658.  *  Enter with the spell number that wants to teleport away
  659.  *  Returns no value.
  660.  */
  661. static tdirect(spnum)
  662.     int spnum;
  663.     {
  664.     int x,y;
  665.     register int m;
  666.     if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  667.     if (isconfuse()) return;
  668.     dirsub(&x,&y);
  669.     if ((m=mitem[x][y])==0)
  670.         {   lprcat("  There wasn't anything there!");   return;  }
  671.     ifblind(x,y);
  672.     if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
  673.     fillmonst(m);  mitem[x][y]=0; know[x][y] &= ~KNOWHERE;
  674.     }
  675.  
  676. /*
  677.  *  omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
  678.  *      int sp,dam;
  679.  *      char *str;
  680.  *
  681.  *  Routine to cast a spell and then hit the monster in all directions
  682.  *  Enter with the spell number in sp, the damage done to wach square in dam,
  683.  *    and the lprintf string to identify the spell in str.
  684.  *  Returns no value.
  685.  */
  686. static omnidirect(spnum,dam,str)
  687.     int spnum,dam;
  688.     char *str;
  689.     {
  690.     extern char lastmonst[] ;
  691.     register int x,y,m;
  692.     if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
  693.     for (x=playerx-1; x<playerx+2; x++)
  694.         for (y=playery-1; y<playery+2; y++)
  695.             {
  696.             if (m=mitem[x][y])
  697.                 if (nospell(spnum,m) == 0)
  698.                     {
  699.                     ifblind(x,y);
  700.                     cursors(); lprc('\n'); lprintf(str,lastmonst);
  701.                     hitm(x,y,dam);  nap(800);
  702.                     }
  703.                 else  { lasthx=x;  lasthy=y; }
  704.             }
  705.     }
  706.  
  707. /*
  708.  *  dirsub(x,y)      Routine to ask for direction, then modify playerx,
  709.  *                   playery for it
  710.  *      int *x,*y;
  711.  *
  712.  *  Function to ask for a direction and modify an x,y for that direction
  713.  *  Enter with the coordinate destination (x,y).
  714.  *  Returns index into diroffx[] (0-8).
  715.  */
  716. dirsub(x,y)
  717.     int *x,*y;
  718.     {
  719.     register int i;
  720.     lprcat("\nIn What Direction? ");
  721.     for (i=0; ; )
  722.         switch(ttgetch())
  723.             {
  724.             case 'b':   i++;
  725.             case 'n':   i++;
  726.             case 'y':   i++;
  727.             case 'u':   i++;
  728.             case 'h':   i++;
  729.             case 'k':   i++;
  730.             case 'l':   i++;
  731.             case 'j':   i++;        goto out;
  732.             };
  733. out:
  734.     *x = playerx+diroffx[i];        *y = playery+diroffy[i];
  735.     vxy(x,y);  return(i);
  736.     }
  737.  
  738. /*
  739.  *  dirpoly(spnum)      Routine to ask for a direction and polymorph a monst
  740.  *      int spnum;
  741.  *
  742.  *  Subroutine to polymorph a monster and ask for the direction its in
  743.  *  Enter with the spell number in spmun.
  744.  *  Returns no value.
  745.  */
  746. static dirpoly(spnum)
  747.     int spnum;
  748.     {
  749.     int x,y,m;
  750.     if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  751.     if (isconfuse()) return;    /* if he is confused, he can't aim his magic */
  752.     dirsub(&x,&y);
  753.     if (mitem[x][y]==0)
  754.         {   lprcat("  There wasn't anything there!");   return;  }
  755.     ifblind(x,y);
  756.     if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
  757. # ifdef MSDOS
  758.     do {
  759.         m = rnd(MAXMONST+7);
  760.         mitem[x][y] = m;
  761.     } while ( monster[m].genocided );
  762. # else
  763.     while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
  764. # endif
  765.     hitp[x][y] = monster[m].hitpoints;
  766.     show1cell(x,y);  /* show the new monster */
  767.     }
  768.  
  769. /*
  770.  *  annihilate()    Routine to annihilate all monsters around player (playerx,playery)
  771.  *
  772.  *  Gives player experience, but no dropped objects
  773.  *  Returns the experience gained from all monsters killed
  774.  */
  775. annihilate()
  776.     {
  777.     int i,j;
  778.     register long k;
  779.     register char *p;
  780.     for (k=0, i=playerx-1; i<=playerx+1; i++)
  781.       for (j=playery-1; j<=playery+1; j++)
  782.         if (!vxy(&i,&j)) /* if not out of bounds */
  783.             if (*(p= &mitem[i][j])) /* if a monster there */
  784.                 if (*p<DEMONLORD+2)
  785.                     {
  786.                     k += monster[*p].experience;    *p=know[i][j] &= ~KNOWHERE;
  787.                     }
  788.                 else
  789.                     {
  790.                     lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
  791.                     hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
  792.                     }
  793.     if (k>0)
  794.         {
  795.         lprcat("\nYou hear loud screams of agony!");    raiseexperience((long)k);
  796.         }
  797.     return(k);
  798.     }
  799.  
  800. /*
  801.  *  genmonst()      Function to ask for monster and genocide from game
  802.  *
  803.  *  This is done by setting a flag in the monster[] structure
  804.  */
  805. static genmonst()
  806.     {
  807.     register int i,j;
  808.     cursors();  lprcat("\nGenocide what monster? ");
  809.     for (i=0; (!isalpha(i)) && (i!=' '); i=ttgetch());
  810.     lprc(i);
  811.     for (j=0; j<MAXMONST; j++)  /* search for the monster type */
  812.         if (monstnamelist[j]==i)    /* have we found it? */
  813.             {
  814.             monster[j].genocided=1; /* genocided from game */
  815.             lprintf("  There will be no more %s's",monster[j].name);
  816.             /* now wipe out monsters on this level */
  817.             newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
  818.             return;
  819.             }
  820.     lprcat("  You sense failure!");
  821.     }
  822.